/* SQUIB - Scala's Quirky User Interface Builder 
    Copyright (C) 2008 Tim Dalton

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
*/
    
import java.lang.reflect.Method

import scala.collection.mutable.{HashMap, ListBuffer}


package tfd.scala.squib {

    trait HasAttributes extends RootTrait {
        private var methHash:HashMap[String, Method] = null

        /* 
         TODO: Analyze the need to cache Methods discovered via reflection. There is
         no mechanism for methodHash contents for "aging out" and it could be a waste
         of heap space
         */
        private lazy val methodHash = new HashMap[String, Method]

        def applyAttributes(component:Object, attrs: ListBuffer[Attribute]):Unit = {
            checkInitMethodHash(component)
            doApplyAttributes(component, attrs)
        }

        protected def doApplyAttributes(component: Object, attrs: ListBuffer[Attribute]):Unit = {
            eventqueue.invokeAndWaitIfNotEDT {
                for (val i<-attrs.elements) {
                    val attr_string = i._1.toString().substring(1).toLowerCase
                    if (methodHash.contains(attr_string)) {
                        //System.out.println("invoking: " + methodHash(attr_string).getName)
                        //System.out.println("with parms: " + i._2)
                        val parms = new Array[Object](1)
                        parms(0) = i._2.asInstanceOf[Object]
                        try {
                            methodHash(attr_string).invoke(component, parms:_*)
                        } catch {
                            case e: Exception => System.out.println(e.toString + " parm type = " + parms(0).getClass.getName)
                        }
                    }
                }
            }
        }
        
        protected def getKeyIfAttribute(name:String):String = {
            if (name.endsWith("_$eq")) {
                name.substring(0, name.length - 4).toLowerCase  
            } else if (name.startsWith("set")) {
                name.substring(3).toLowerCase
            } else {
                null
            }
        }
        
        protected def checkInitMethodHash(component: Object) = {
            if (methodHash.size == 0) {
                val methods = component.getClass.getMethods
                for (val i<- Iterator.range(0, methods.length)) {
                    if (methods(i).getParameterTypes().size == 1) {
                        val hashKey = getKeyIfAttribute( methods(i).getName)
                        if (hashKey != null) {
                            methodHash += hashKey -> methods(i)
                        }
                    }
                }
            }
        }
        
        protected def doSetters(component: Object, attrs: ListBuffer[Attribute]):Unit = {
            checkInitMethodHash(component)
            doApplyAttributes(component, attrs)
        }
    }
}
